﻿using System.IO;
using System.IO.Compression;
using System;
using System.Text;

namespace Marbles.Core.Helpers
{
    public class Compression
    {

        public static string Compress(string value, CompressionMethod CompressionMethod)
        {
            byte[] buffer = Encoding.UTF8.GetBytes(value);
            MemoryStream ms = new MemoryStream();

            switch (CompressionMethod)
            {
                case CompressionMethod.None: return value.Trim(); 
                case CompressionMethod.Zip:
                    using (GZipStream zip = new GZipStream(ms, CompressionMode.Compress, true))
                    {
                        zip.Write(buffer, 0, buffer.Length);
                    }
                    break;
                case CompressionMethod.Deflate:
                    using (DeflateStream zip = new DeflateStream(ms, CompressionMode.Compress, true))
                    {
                        zip.Write(buffer, 0, buffer.Length);
                    }
                    break;
            }

            ms.Position = 0;
            MemoryStream outStream = new MemoryStream();

            byte[] compressed = new byte[ms.Length];
            ms.Read(compressed, 0, compressed.Length);

            byte[] gzBuffer = new byte[compressed.Length + 4];
            Buffer.BlockCopy(compressed, 0, gzBuffer, 4, compressed.Length);
            Buffer.BlockCopy(BitConverter.GetBytes(buffer.Length), 0, gzBuffer, 0, 4);
            return Convert.ToBase64String(gzBuffer);

        }

        public static string Decompress(string value, CompressionMethod CompressionMethod)
        {
            byte[] gzBuffer = Convert.FromBase64String(value);

            switch (CompressionMethod)
            {
                case CompressionMethod.None: return value.Trim(); 
                case CompressionMethod.Zip:
                    using (MemoryStream ms = new MemoryStream())
                    {
                        int msgLength = BitConverter.ToInt32(gzBuffer, 0);
                        ms.Write(gzBuffer, 4, gzBuffer.Length - 4);

                        byte[] buffer = new byte[msgLength];

                        ms.Position = 0;
                        using (GZipStream zip = new GZipStream(ms, CompressionMode.Decompress))
                        {
                            zip.Read(buffer, 0, buffer.Length);
                        }

                        return Encoding.UTF8.GetString(buffer);
                    }
                case CompressionMethod.Deflate:
                    using (MemoryStream ms = new MemoryStream())
                    {
                        int msgLength = BitConverter.ToInt32(gzBuffer, 0);
                        ms.Write(gzBuffer, 4, gzBuffer.Length - 4);

                        byte[] buffer = new byte[msgLength];

                        ms.Position = 0;
                        using (DeflateStream zip = new DeflateStream(ms, CompressionMode.Decompress))
                        {
                            zip.Read(buffer, 0, buffer.Length);
                        }

                        return Encoding.UTF8.GetString(buffer);
                    }
            }

            return string.Empty;
        }
    }


    public enum CompressionMethod
    {
        None, Zip, Deflate
    }
}
